package com.lovegu.netty.serialize;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.lovegu.netty.res.RpcRequest;
import com.lovegu.netty.res.RpcResponse;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

/**
 * @author 老顾 1437594522@qq.com
 * @description
 * @date 2022/11/23 8:49
 */
public class KryoSerializer implements Serializer{

    private static final ThreadLocal<Kryo> KRYO_THREAD_LOCAL = ThreadLocal.withInitial(()->{
        Kryo kryo = new Kryo();
        kryo.register(RpcResponse.class);
        kryo.register(RpcRequest.class);
        //默认为true，是否关闭注册行为，关闭之后可能存在序列化问题，一般推荐设置为true
        kryo.setReferences(true);
        //默认值为false，是否关闭循环引用，可以提高性能，一般不推荐设置为true
        kryo.setRegistrationRequired(false);
        return kryo;
    });

    /**
     * 序列化
     *
     * @param obj
     * @return
     */
    @Override
    public byte[] serialize(Object obj) {
        try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
             Output output = new Output(byteArrayOutputStream)){
            Kryo kryo = KRYO_THREAD_LOCAL.get();
            //Object -> byte：将对象序列化为byte数组
            kryo.writeObject(output,obj);
            KRYO_THREAD_LOCAL.remove();
            return output.toBytes();
        }catch (Exception e){
            throw new SerializeException("序列化失败");
        }
    }

    /**
     * 反序列化
     *
     * @param bytes
     * @param clazz
     * @return
     */
    @Override
    public <T> T deserialize(byte[] bytes, Class<T> clazz) {
        try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        Input input = new Input(byteArrayInputStream)){
            Kryo kryo = KRYO_THREAD_LOCAL.get();
            //byte -> object：从byte数组中反序列化出对象
            Object o = kryo.readObject(input,clazz);
            KRYO_THREAD_LOCAL.remove();
            return clazz.cast(o);
        }catch (Exception e){
            throw new SerializeException("反序列化失败");
        }
    }

    static class SerializeException extends RuntimeException {
        public SerializeException(String message){
            super(message);
        }
    }
}
